class Mvvm{
    constructor(options) {
        this.$el = options.el;
        this.$data = options.data;
        if(this.$el){
            //1.数据劫持
            new Observer(this.$data);
            //2.模板编译   数据  模板
            new Compile(this.$el,this);
        }
    }   
}

//发布订阅模式    观察者模式
class Dep{
    constructor(){
        this.watchers = [];
    }

    add(watcher){
        this.watchers.push(watcher);
    }

    //通知
    notify(){
        this.watchers.forEach(watcher => {
            watcher.update();
        })
    }
}

/*
 new Watcher(expr,vm,(newVal) => {
    this.updater.model(node,newVal);
});

**/ 

//观察者
class Watcher{
    constructor(expr,vm,cb){
        this.cb = cb;
        this.expr = expr;
        this.vm = vm;
        this.oldVal = this.getVal();
    }

    getVal(){
        Dep.target = this;
        //旧值
        this.oldVal = compileUtil.getVal(this.expr,this.vm);
        Dep.target = null;
    }

    //更新函数
    update(){
        //最新的值
        let newVal = compileUtil.getVal(this.expr,this.vm);
        if(newVal !== this.oldVal){
            //更新
            this.cb && this.cb(newVal);
        }
    }
}




//vm.$watch()

//模板编译
class Compile{
    constructor(el,vm){
        //判断当前的el是dom节点还是字符串

        this.el = this.isElementNode(el) ? el :document.querySelector(el);

        this.vm = vm;

        //1.把el内的模板放在文档片段内
        this.fragment = this.nodeToFragment(this.el);

        //2.数据  模板  进行编译
        this.compile(this.fragment);
        //3.把文档片段插入到页面内
        this.el.appendChild(this.fragment);
    }

    isDirective(name){
        return name.startsWith('v-');
    }

    //编译元素节点
    elementCompile(child){
        let attrs = [...child.attributes];  //获取所有的属性
        console.log("attrs",attrs)
        attrs.forEach(attr =>{
            console.dir(attr,'attr')

            let {name,value:expr} = attr;

            if(this.isDirective(name)){  //v-model input child  v-html  v-text
                let [,directive] = name.split('-'); //[v,model]
                //指令 child.value = this.vm.$data expr的值
                compileUtil[directive](expr,this.vm,child);
            }
        })
    }

    //编译文本节点
    textCompile(node){
        //{{username}} 
        let content = node.textContent;
        if(/\{\{(.+?)\}\}/.test(content)){
            //{{}}  vm.$data   username  
            compileUtil.content(this.vm,node);
        }
    }

    //compile

    compile(node){
        //1.拿到所有的子节点
        let childNodes = [...node.childNodes];
        console.log(childNodes,"childNodes");

        childNodes.forEach(child => {
            if(this.isElementNode(child)){
                //元素节点
                this.compile(child);
                this.elementCompile(child)
            }else{
                //文本节点
                this.textCompile(child);
            }
        })
    }

    nodeToFragment(el){
        let fragment = document.createDocumentFragment();
        let childNodes = [...el.childNodes];
        childNodes.forEach(child => {
            fragment.appendChild(child);
        })
        return fragment
    }

    isElementNode(el){
        return el.nodeType === 1
    }
}


const compileUtil = {

    //获取值
    getVal(expr,vm){  //address.city
        /**
         * {
                username:'zs',
                address:{
                    city:'北京',
                    area:'海淀区'
                }
            }
         * 
         * 
        */
        //vm.$data[expr]

        //address.city  [address,city]

        return expr.split('.').reduce((prev,cur) => {
            return prev[cur]
        },vm.$data)

    },

    //设置值

    setVal(expr,vm,value){
        //username  address.city

        expr.split('.').reduce((prev,cur,index) => {
            if(expr.split('.').length - 1 === index){
                //最后一个city
                prev[cur] = value;
            }else{
                return prev[cur]
            }
        },vm.$data)
    },
    model(expr,vm,node){  //v-model
       // value 
       let value = this.getVal(expr,vm);
       new Watcher(expr,vm,(newVal) => {
            this.updater.model(node,newVal);
       });
       this.updater.model(node,value);

       node.addEventListener('input',(e) => {
        //    e.target.value  vm.$data expr
            //设置值
            this.setVal(expr,vm,e.target.value)
       }) 
    },

    content(vm,node){
        let content = node.textContent;
        let text = content.replace(/\{\{(.+?)\}\}/g,(...argv) => {
            //{{username}}  username
            let value = this.getVal(argv[1],vm);

            new Watcher(argv[1],vm,(newVal) => {
                this.updater.content(node,newVal);
           });
            return value
        });

        

        this.updater.content(node,text);

    },
    updater:{
        model(node,value){
            node.value = value;
        },
        content(node,value){
            node.textContent = value;
        }
    }
}

//数据劫持
class Observer{
    constructor(data){
        this.observer(data)
    }

    observer(data){
        //1.判断是否是对象
        if(typeof data === 'object'){
            for(let key in data){
                //是对象
                this.observerData(data,key,data[key])
            }
        }
    }

    observerData(data,key,value){
        let dep = new Dep();
        //value 对象
        this.observer(value);
        Object.defineProperty(data,key,{
            set(newVal){
                if(newVal !== value){
                    value = newVal;
                    dep.notify();
                }
            },
            get(){
                Dep.target && dep.add(Dep.target); //Dep.target wather
                return value
            }
        })
    }
}